package compilador.gerador;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import compilador.semantico.TabelaSemantica;
import compilador.semantico.Tipo;

public class GeradorDeCodigo {
	
	public static final String INVARIANTE_SEM_NOME = "invarianteN";
	public static final String SUFIX_INV = "Invariante";

	private static final GeradorDeCodigo instance = new GeradorDeCodigo();
	private static final String MARK = "\\";
	
	public static GeradorDeCodigo getInstance() {
		return instance;
	}

	// object stuff

	private Map<String, ClasseCodigo> classes = new HashMap<String, ClasseCodigo>();
	private String currentClass;
	private StringBuilder buffer = null;
	
	
	private GeradorDeCodigo()  {
		// nothing to do
	}

	public void createClassesStub() {
		TabelaSemantica tabela = TabelaSemantica.getInstance();
		Collection<Tipo> tipos = tabela.getTipos();
		for(Tipo tipo : tipos) {
			this.classes.put(tipo.getNome(), new ClasseCodigo(tipo));
		}
	}

	public void writeClasses() {
		for(String str : classes.keySet()) {
			ClasseCodigo code = classes.get(str);
			OutputStreamWriter out = null;
			try {
				File f = new File(code.getFilename());
				out = new OutputStreamWriter(new FileOutputStream(f));
				out.write(code.getCode());
			} catch (IOException e) {
				System.err.println("Erro escrevendo arquivo " + code.getFilename());
				System.err.println("Mensagem de erro: " + e.getLocalizedMessage());
				System.out.println(code .getCode());
			} finally {
				try {
					if ( out != null) out.close();
				} catch (IOException e) {}
			}
		}
	}

	public void setCurrentClass(String classe) {
		this.currentClass = classe;		
	}

	public ClasseCodigo getClasseCodigo() {
		return this.classes.get(this.currentClass);
	}

	public void appendCode(String code) {
		if ( this.buffer == null ) {
			this.buffer  = new StringBuilder();
		}
		this.buffer.append(code);
	}

	public void flushInv() {
		ClasseCodigo code = this.classes.get(this.currentClass);
		code.addInvBody(buffer.toString());
		this.buffer = null;
	}

	public void insertMark() {
		insertMark(MARK);
	}

	public void removeMark() {
		removeMark(MARK);
	}

	public String getMarked() {
		return getMarked(MARK); 
	}

	public void removeMarked() {
		removeMarked(MARK);
	}

	public void insertMark(String mark) {
		this.appendCode(mark);		
	}
	
	public void removeMark(String mark) {
		if ( this.buffer.indexOf(mark) != -1)
		this.buffer.deleteCharAt(this.buffer.indexOf(mark));		
	}

	public String getMarked(String mark) {
		return this.buffer.substring(this.buffer.lastIndexOf(mark)+1); 
	}

	public void removeMarked(String mark) {
		this.buffer.delete(this.buffer.indexOf(mark)+1, this.buffer.length());
	}

}
